package com.tiger.admin.http.logs;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.tiger.admin.Db;
import com.tiger.admin.dto.PaginationResult;
import com.tiger.admin.http.logs.dto.ExportDto;
import com.tiger.admin.http.logs.dto.PageDto;
import com.tiger.admin.http.logs.type.BackendLogRes;
import com.tiger.db.entity.ExportTask;
import com.tiger.db.entity.Member;
import com.tiger.mongodb.entity.BackendLog;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.usermodel.WorkbookFactory;
import org.bson.types.ObjectId;
import org.springframework.beans.BeanUtils;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class BackendLogService {
    private final short exportSize = 5000;
    private final MongoTemplate mongoTemplate;
    private final Db db;

    public BackendLogService(MongoTemplate mongoTemplate, Db db) {
        this.mongoTemplate = mongoTemplate;
        this.db = db;
    }


    public PaginationResult<BackendLogRes> page(PageDto page) {
        long startTime = page.getStartTime();
        long endTime = page.getEndTime();

        PaginationResult<BackendLogRes> result = new PaginationResult<>();

        Criteria criteria = new Criteria();
        Sort sort = Sort.by(Sort.Direction.DESC, "_id"); // 升序


        if(page.getKey() != null && !page.getKey().isEmpty()) {
            Member member = db.member.getOne(new LambdaQueryWrapper<Member>().select(Member::getId, Member::getAccount, Member::getName).eq(Member::getAccount, page.getKey()));
            if(member == null) return result;
            criteria.and("memberId").is(member.getId());
        }

        if(page.getIp() != null && !page.getIp().isEmpty()) {
            criteria.and("ip").is(page.getIp());
        }

        if(startTime != 0 && endTime != 0) {
            if(startTime == endTime) {
                criteria.and("time").is(startTime);
            }else {
                criteria.and("time").gte(startTime).lt(endTime);
            }
        }



        Query query = new Query(criteria);
        query.with(sort);


        result.setTotal(mongoTemplate.count(query, BackendLog.class));

        if(result.getTotal() > 0) {
            query.skip((page.getPageNo() - 1) * page.getPageSize()).limit(page.getPageSize());

            List<BackendLog> logs = mongoTemplate.find(query, BackendLog.class);
            if(!logs.isEmpty()) {
                List<Long> memberIds = logs.stream().map(BackendLog::getMemberId).collect(Collectors.toList());
                List<Member> members = db.member.list(new LambdaQueryWrapper<Member>().select(Member::getId, Member::getAccount, Member::getName).in(Member::getId, memberIds));

                List<BackendLogRes> rows = new ArrayList<>();


                for(BackendLog log : logs) {
                    BackendLogRes row = new BackendLogRes();
                    BeanUtils.copyProperties(log, row);
                    Optional<Member> member = members.stream() // 将List转换为流
                            .filter(item -> Objects.equals(item.getId(), log.getMemberId())).findFirst();

                    if(member.isPresent()) {
                        row.setAccount(member.get().getAccount());
                        row.setName(member.get().getName());
                    }

                    rows.add(row);
                }

                result.setRows(rows);

            }
        }

        return result;
    }


    @Async
    public void export(long id, ExportDto dto, String filePath) throws IOException {
        String _id = null;
        long memberId = 0;

        if(dto.getKey() != null && !dto.getKey().isEmpty()) {
            Member member = db.member.getOne(new LambdaQueryWrapper<Member>().select(Member::getId, Member::getAccount, Member::getName).eq(Member::getAccount, dto.getKey()));
            if(member == null) return;
            memberId = member.getId();
        }

        while (true) {
            List<BackendLogRes> rows = query(dto, memberId, _id);
            writeToExcel(filePath, 0, rows);
            int size = rows.size();
            if(size >= exportSize) {
                _id = rows.get(size - 1).getId();
            }else {
                break;
            }
        }

        LambdaUpdateWrapper<ExportTask> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(ExportTask::getId, id);
        updateWrapper.set(ExportTask::getStatus, 1);


        boolean r = db.exportTask.update(updateWrapper);

    }

    public List<BackendLogRes> query(ExportDto dto, long memberId, String _id) {
        List<BackendLogRes> rows = new ArrayList<>();


        Criteria criteria = new Criteria();

        if(_id != null && !_id.isEmpty()) {
            criteria.and("_id").gt(new ObjectId(_id));
        }

        if(memberId > 0) {
            criteria.and("memberId").is(memberId);
        }

        if(dto.getIp() != null && !dto.getIp().isEmpty()) {
            criteria.and("ip").is(dto.getIp());
        }


        long startTime = dto.getStartTime();
        long endTime = dto.getEndTime();

        if(startTime > 0 || endTime > 0) {
            criteria.and("time");
            if(startTime == endTime) {
                criteria.is(startTime);
            }else {

                if(startTime > 0) {
                    criteria.gte(startTime);
                }

                if(endTime > 0) {
                    criteria.lt(startTime);
                }
            }
        }




        Query query = new Query(criteria);

        query.limit(exportSize);
        List<BackendLog> logs = mongoTemplate.find(query, BackendLog.class);

        if(!logs.isEmpty()) {
            List<Long> memberIds = logs.stream().map(BackendLog::getMemberId).collect(Collectors.toList());
            List<Member> members = db.member.list(new LambdaQueryWrapper<Member>().select(Member::getId, Member::getAccount, Member::getName).in(Member::getId, memberIds));




            for(BackendLog log : logs) {
                BackendLogRes row = new BackendLogRes();
                BeanUtils.copyProperties(log, row);
                Optional<Member> member = members.stream() // 将List转换为流
                        .filter(item -> Objects.equals(item.getId(), log.getMemberId())).findFirst();

                if(member.isPresent()) {
                    row.setAccount(member.get().getAccount());
                    row.setName(member.get().getName());
                }

                rows.add(row);
            }

        }


        return rows;

    }

    /**
     * 向Excel文件的指定工作表写入多行数据。
     *
     * @param filePath    Excel文件路径
     * @param sheetIndex  工作表索引
     * @param data        要写入的数据，以二维数组的形式
     * @throws IOException 如果文件操作失败
     */
    public static void writeToExcel(String filePath, int sheetIndex, List<BackendLogRes> data) throws IOException {
        FileInputStream fis = new FileInputStream(new File(filePath));
        Workbook workbook = WorkbookFactory.create(fis);
        Sheet sheet = workbook.getSheetAt(sheetIndex); // 获取工作表

        // 计算要写入数据的起始行号
        int startRow = sheet.getLastRowNum() + 1;

        SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");

        // 遍历数据列表，逐行写入
        for (int i = 0; i < data.size(); i++) {
            BackendLogRes rowData = data.get(i);
            Row row = sheet.getRow(startRow + i); // 获取或创建行
            if (row == null) {
                row = sheet.createRow(startRow + i); // 如果行不存在，则创建新行
            }

            row.createCell(0).setCellValue(rowData.getAccount());
            row.createCell(1).setCellValue(rowData.getUrl());
            row.createCell(2).setCellValue(sdf.format(new Date(rowData.getTime() * 1000)));
            row.createCell(3).setCellValue(rowData.getIp());
            row.createCell(4).setCellValue(rowData.getLocation());
            row.createCell(5).setCellValue(rowData.getBrowser());
            row.createCell(6).setCellValue(rowData.getData());
            row.createCell(7).setCellValue(rowData.getResult());

        }

        // 将更改写回文件
        FileOutputStream fos = new FileOutputStream(filePath);
        workbook.write(fos);
        fos.close();

        // 关闭资源
        workbook.close();
        fis.close();
    }
}
